/********************************************************************* * * Copyright (C) 2002 Andrew Khan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ***************************************************************************/ package jxl.write.biff; import java.io.File; import java.net.URL; import java.net.MalformedURLException; import java.util.ArrayList; import jxl.common.Assert; import jxl.common.Logger; import jxl.CellType; import jxl.Hyperlink; import jxl.Range; import jxl.WorkbookSettings; import jxl.biff.CellReferenceHelper; import jxl.biff.IntegerHelper; import jxl.biff.SheetRangeImpl; import jxl.biff.StringHelper; import jxl.biff.Type; import jxl.biff.WritableRecordData; import jxl.write.Label; import jxl.write.WritableHyperlink; import jxl.write.WritableCell; import jxl.write.WritableSheet; /** * A hyperlink */ public class HyperlinkRecord extends WritableRecordData { /** * The logger */ private static Logger logger = Logger.getLogger(HyperlinkRecord.class); /** * The first row */ private int firstRow; /** * The last row */ private int lastRow; /** * The first column */ private int firstColumn; /** * The last column */ private int lastColumn; /** * The URL referred to by this hyperlink */ private URL url; /** * The local file referred to by this hyperlink */ private File file; /** * The location in this workbook referred to by this hyperlink */ private String location; /** * The cell contents of the cell which activate this hyperlink */ private String contents; /** * The type of this hyperlink */ private LinkType linkType; /** * The data for this hyperlink */ private byte[] data; /** * The range of this hyperlink. When creating a hyperlink, this will * be null until the hyperlink is added to the sheet */ private Range range; /** * The sheet containing this hyperlink */ private WritableSheet sheet; /** * Indicates whether this record has been modified since it was copied */ private boolean modified; /** * The excel type of hyperlink */ private static class LinkType {}; private static final LinkType urlLink = new LinkType(); private static final LinkType fileLink = new LinkType(); private static final LinkType uncLink = new LinkType(); private static final LinkType workbookLink = new LinkType(); private static final LinkType unknown = new LinkType(); /** * Constructs this object from the readable spreadsheet * * @param hl the hyperlink from the read spreadsheet */ protected HyperlinkRecord(Hyperlink h, WritableSheet s) { super(Type.HLINK); if (h instanceof jxl.read.biff.HyperlinkRecord) { copyReadHyperlink(h, s); } else { copyWritableHyperlink(h, s); } } /** * Copies a hyperlink read in from a read only sheet */ private void copyReadHyperlink(Hyperlink h, WritableSheet s) { jxl.read.biff.HyperlinkRecord hl = (jxl.read.biff.HyperlinkRecord) h; data = hl.getRecord().getData(); sheet = s; // Populate this hyperlink with the copied data firstRow = hl.getRow(); firstColumn = hl.getColumn(); lastRow = hl.getLastRow(); lastColumn = hl.getLastColumn(); range = new SheetRangeImpl(s, firstColumn, firstRow, lastColumn, lastRow); linkType = unknown; if (hl.isFile()) { linkType = fileLink; file = hl.getFile(); } else if (hl.isURL()) { linkType = urlLink; url = hl.getURL(); } else if (hl.isLocation()) { linkType = workbookLink; location = hl.getLocation(); } modified = false; } /** * Copies a hyperlink read in from a writable sheet. * Used when copying writable sheets * * @param hl the hyperlink from the read spreadsheet */ private void copyWritableHyperlink(Hyperlink hl, WritableSheet s) { HyperlinkRecord h = (HyperlinkRecord) hl; firstRow = h.firstRow; lastRow = h.lastRow; firstColumn = h.firstColumn; lastColumn = h.lastColumn; if (h.url != null) { try { url = new URL(h.url.toString()); } catch (MalformedURLException e) { // should never get a malformed url as a result url.toString() Assert.verify(false); } } if (h.file != null) { file = new File(h.file.getPath()); } location = h.location; contents = h.contents; linkType = h.linkType; modified = true; sheet = s; range = new SheetRangeImpl(s, firstColumn, firstRow, lastColumn, lastRow); } /** * Constructs a URL hyperlink to a range of cells * * @param col the column containing this hyperlink * @param row the row containing this hyperlink * @param lastcol the last column which activates this hyperlink * @param lastrow the last row which activates this hyperlink * @param url the hyperlink * @param desc the description */ protected HyperlinkRecord(int col, int row, int lastcol, int lastrow, URL url, String desc) { super(Type.HLINK); firstColumn = col; firstRow = row; lastColumn = Math.max(firstColumn, lastcol); lastRow = Math.max(firstRow, lastrow); this.url = url; contents = desc; linkType = urlLink; modified = true; } /** * Constructs a File hyperlink to a range of cells * * @param col the column containing this hyperlink * @param row the row containing this hyperlink * @param lastcol the last column which activates this hyperlink * @param lastrow the last row which activates this hyperlink * @param file the hyperlink * @param desc the description */ protected HyperlinkRecord(int col, int row, int lastcol, int lastrow, File file, String desc) { super(Type.HLINK); firstColumn = col; firstRow = row; lastColumn = Math.max(firstColumn, lastcol); lastRow = Math.max(firstRow, lastrow); contents = desc; this.file = file; if (file.getPath().startsWith("\\\\")) { linkType = uncLink; } else { linkType = fileLink; } modified = true; } /** * Constructs a hyperlink to some cells within this workbook * * @param col the column containing this hyperlink * @param row the row containing this hyperlink * @param lastcol the last column which activates this hyperlink * @param lastrow the last row which activates this hyperlink * @param desc the contents of the cell which describe this hyperlink * @param sheet the sheet containing the cells to be linked to * @param destcol the column number of the first destination linked cell * @param destrow the row number of the first destination linked cell * @param lastdestcol the column number of the last destination linked cell * @param lastdestrow the row number of the last destination linked cell */ protected HyperlinkRecord(int col, int row, int lastcol, int lastrow, String desc, WritableSheet s, int destcol, int destrow, int lastdestcol, int lastdestrow) { super(Type.HLINK); firstColumn = col; firstRow = row; lastColumn = Math.max(firstColumn, lastcol); lastRow = Math.max(firstRow, lastrow); setLocation(s, destcol, destrow, lastdestcol, lastdestrow); contents = desc; linkType = workbookLink; modified = true; } /** * Determines whether this is a hyperlink to a file * * @return TRUE if this is a hyperlink to a file, FALSE otherwise */ public boolean isFile() { return linkType == fileLink; } /** * Determines whether this is a hyperlink to a UNC * * @return TRUE if this is a hyperlink to a UNC, FALSE otherwise */ public boolean isUNC() { return linkType == uncLink; } /** * Determines whether this is a hyperlink to a web resource * * @return TRUE if this is a URL */ public boolean isURL() { return linkType == urlLink; } /** * Determines whether this is a hyperlink to a location in this workbook * * @return TRUE if this is a link to an internal location */ public boolean isLocation() { return linkType == workbookLink; } /** * Returns the row number of the top left cell * * @return the row number of this cell */ public int getRow() { return firstRow; } /** * Returns the column number of the top left cell * * @return the column number of this cell */ public int getColumn() { return firstColumn; } /** * Returns the row number of the bottom right cell * * @return the row number of this cell */ public int getLastRow() { return lastRow; } /** * Returns the column number of the bottom right cell * * @return the column number of this cell */ public int getLastColumn() { return lastColumn; } /** * Gets the URL referenced by this Hyperlink * * @return the URL, or NULL if this hyperlink is not a URL */ public URL getURL() { return url; } /** * Returns the local file eferenced by this Hyperlink * * @return the file, or NULL if this hyperlink is not a file */ public File getFile() { return file; } /** * Gets the binary data to be written to the output file * * @return the data to write to file */ public byte[] getData() { if (!modified) { return data; } // Build up the jxl.common.data byte[] commonData = new byte[32]; // Set the range of cells this hyperlink applies to IntegerHelper.getTwoBytes(firstRow, commonData, 0); IntegerHelper.getTwoBytes(lastRow, commonData, 2); IntegerHelper.getTwoBytes(firstColumn, commonData, 4); IntegerHelper.getTwoBytes(lastColumn, commonData, 6); // Some inexplicable byte sequence commonData[8] = (byte) 0xd0; commonData[9] = (byte) 0xc9; commonData[10] = (byte) 0xea; commonData[11] = (byte) 0x79; commonData[12] = (byte) 0xf9; commonData[13] = (byte) 0xba; commonData[14] = (byte) 0xce; commonData[15] = (byte) 0x11; commonData[16] = (byte) 0x8c; commonData[17] = (byte) 0x82; commonData[18] = (byte) 0x0; commonData[19] = (byte) 0xaa; commonData[20] = (byte) 0x0; commonData[21] = (byte) 0x4b; commonData[22] = (byte) 0xa9; commonData[23] = (byte) 0x0b; commonData[24] = (byte) 0x2; commonData[25] = (byte) 0x0; commonData[26] = (byte) 0x0; commonData[27] = (byte) 0x0; // Set up the option flags to indicate the type of this URL. There // is no description int optionFlags = 0; if (isURL()) { optionFlags = 3; if (contents != null) { optionFlags |= 0x14; } } else if (isFile()) { optionFlags = 1; if (contents != null) { optionFlags |= 0x14; } } else if (isLocation()) { optionFlags = 8; } else if (isUNC()) { optionFlags = 259; } IntegerHelper.getFourBytes(optionFlags, commonData, 28); if (isURL()) { data = getURLData(commonData); } else if (isFile()) { data = getFileData(commonData); } else if (isLocation()) { data = getLocationData(commonData); } else if (isUNC()) { data = getUNCData(commonData); } return data; } /** * A standard toString method * * @return the contents of this object as a string */ public String toString() { if (isFile()) { return file.toString(); } else if (isURL()) { return url.toString(); } else if (isUNC()) { return file.toString(); } else { return ""; } } /** * Gets the range of cells which activate this hyperlink * The get sheet index methods will all return -1, because the * cells will all be present on the same sheet * * @return the range of cells which activate the hyperlink or NULL * if this hyperlink has not been added to the sheet */ public Range getRange() { return range; } /** * Sets the URL of this hyperlink * * @param url the url */ public void setURL(URL url) { URL prevurl = this.url; linkType = urlLink; file = null; location = null; contents = null; this.url = url; modified = true; if (sheet == null) { // hyperlink has not been added to the sheet yet, so simply return return; } // Change the label on the sheet if it was a string representation of the // URL WritableCell wc = sheet.getWritableCell(firstColumn, firstRow); if (wc.getType() == CellType.LABEL) { Label l = (Label) wc; String prevurlString = prevurl.toString(); String prevurlString2 = ""; if (prevurlString.charAt(prevurlString.length() - 1) == '/' || prevurlString.charAt(prevurlString.length() - 1) == '\\') { prevurlString2 = prevurlString.substring(0, prevurlString.length() - 1); } if (l.getString().equals(prevurlString) || l.getString().equals(prevurlString2)) { l.setString(url.toString()); } } } /** * Sets the file activated by this hyperlink * * @param file the file */ public void setFile(File file) { linkType = fileLink; url = null; location = null; contents = null; this.file = file; modified = true; if (sheet == null) { // hyperlink has not been added to the sheet yet, so simply return return; } // Change the label on the sheet WritableCell wc = sheet.getWritableCell(firstColumn, firstRow); Assert.verify(wc.getType() == CellType.LABEL); Label l = (Label) wc; l.setString(file.toString()); } /** * Sets the location of the cells to be linked to within this workbook * * @param desc the label describing the link * @param sheet the sheet containing the cells to be linked to * @param destcol the column number of the first destination linked cell * @param destrow the row number of the first destination linked cell * @param lastdestcol the column number of the last destination linked cell * @param lastdestrow the row number of the last destination linked cell */ protected void setLocation(String desc, WritableSheet sheet, int destcol, int destrow, int lastdestcol, int lastdestrow) { linkType = workbookLink; url = null; file = null; modified = true; contents = desc; setLocation(sheet, destcol, destrow, lastdestcol, lastdestrow); if (sheet == null) { // hyperlink has not been added to the sheet yet, so simply return return; } // Change the label on the sheet WritableCell wc = sheet.getWritableCell(firstColumn, firstRow); Assert.verify(wc.getType() == CellType.LABEL); Label l = (Label) wc; l.setString(desc); } /** * Initializes the location from the data passed in * * @param sheet the sheet containing the cells to be linked to * @param destcol the column number of the first destination linked cell * @param destrow the row number of the first destination linked cell * @param lastdestcol the column number of the last destination linked cell * @param lastdestrow the row number of the last destination linked cell */ private void setLocation(WritableSheet sheet, int destcol, int destrow, int lastdestcol, int lastdestrow) { StringBuffer sb = new StringBuffer(); sb.append('\''); if (sheet.getName().indexOf('\'') == -1) { sb.append(sheet.getName()); } else { // sb.append(sheet.getName().replaceAll("'", "''")); // Can't use replaceAll as it is only 1.4 compatible, so have to // do this the tedious way String sheetName = sheet.getName(); int pos = 0 ; int nextPos = sheetName.indexOf('\'', pos); while (nextPos != -1 && pos < sheetName.length()) { sb.append(sheetName.substring(pos, nextPos)); sb.append("''"); pos = nextPos + 1; nextPos = sheetName.indexOf('\'', pos); } sb.append(sheetName.substring(pos)); } sb.append('\''); sb.append('!'); lastdestcol = Math.max(destcol, lastdestcol); lastdestrow = Math.max(destrow, lastdestrow); CellReferenceHelper.getCellReference(destcol, destrow, sb); sb.append(':'); CellReferenceHelper.getCellReference(lastdestcol, lastdestrow, sb); location = sb.toString(); } /** * A row has been inserted, so adjust the range objects accordingly * * @param r the row which has been inserted */ void insertRow(int r) { // This will not be called unless the hyperlink has been added to the // sheet Assert.verify(sheet != null && range != null); if (r > lastRow) { return; } if (r <= firstRow) { firstRow++; modified = true; } if (r <= lastRow) { lastRow++; modified = true; } if (modified) { range = new SheetRangeImpl(sheet, firstColumn, firstRow, lastColumn, lastRow); } } /** * A column has been inserted, so adjust the range objects accordingly * * @param c the column which has been inserted */ void insertColumn(int c) { // This will not be called unless the hyperlink has been added to the // sheet Assert.verify(sheet != null && range != null); if (c > lastColumn) { return; } if (c <= firstColumn) { firstColumn++; modified = true; } if (c <= lastColumn) { lastColumn++; modified = true; } if (modified) { range = new SheetRangeImpl(sheet, firstColumn, firstRow, lastColumn, lastRow); } } /** * A row has been removed, so adjust the range objects accordingly * * @param r the row which has been inserted */ void removeRow(int r) { // This will not be called unless the hyperlink has been added to the // sheet Assert.verify(sheet != null && range != null); if (r > lastRow) { return; } if (r < firstRow) { firstRow--; modified = true; } if (r < lastRow) { lastRow--; modified = true; } if (modified) { Assert.verify(range != null); range = new SheetRangeImpl(sheet, firstColumn, firstRow, lastColumn, lastRow); } } /** * A column has been removed, so adjust the range objects accordingly * * @param c the column which has been removed */ void removeColumn(int c) { // This will not be called unless the hyperlink has been added to the // sheet Assert.verify(sheet != null && range != null); if (c > lastColumn) { return; } if (c < firstColumn) { firstColumn--; modified = true; } if (c < lastColumn) { lastColumn--; modified = true; } if (modified) { Assert.verify(range != null); range = new SheetRangeImpl(sheet, firstColumn, firstRow, lastColumn, lastRow); } } /** * Gets the hyperlink stream specific to a URL link * * @param cd the data jxl.common.for all types of hyperlink * @return the raw data for a URL hyperlink */ private byte[] getURLData(byte[] cd) { String urlString = url.toString(); int dataLength = cd.length + 20 + (urlString.length() + 1)* 2; if (contents != null) { dataLength += 4 + (contents.length() + 1) * 2; } byte[] d = new byte[dataLength]; System.arraycopy(cd, 0, d, 0, cd.length); int urlPos = cd.length; if (contents != null) { IntegerHelper.getFourBytes(contents.length() + 1, d, urlPos); StringHelper.getUnicodeBytes(contents, d, urlPos + 4); urlPos += (contents.length() + 1) * 2 + 4; } // Inexplicable byte sequence d[urlPos] = (byte) 0xe0; d[urlPos+1] = (byte) 0xc9; d[urlPos+2] = (byte) 0xea; d[urlPos+3] = (byte) 0x79; d[urlPos+4] = (byte) 0xf9; d[urlPos+5] = (byte) 0xba; d[urlPos+6] = (byte) 0xce; d[urlPos+7] = (byte) 0x11; d[urlPos+8] = (byte) 0x8c; d[urlPos+9] = (byte) 0x82; d[urlPos+10] = (byte) 0x0; d[urlPos+11] = (byte) 0xaa; d[urlPos+12] = (byte) 0x0; d[urlPos+13] = (byte) 0x4b; d[urlPos+14] = (byte) 0xa9; d[urlPos+15] = (byte) 0x0b; // Number of characters in the url, including a zero trailing character IntegerHelper.getFourBytes((urlString.length() + 1)*2, d, urlPos+16); // Put the url into the data string StringHelper.getUnicodeBytes(urlString, d, urlPos+20); return d; } /** * Gets the hyperlink stream specific to a URL link * * @param cd the data jxl.common.for all types of hyperlink * @return the raw data for a URL hyperlink */ private byte[] getUNCData(byte[] cd) { String uncString = file.getPath(); byte[] d = new byte[cd.length + uncString.length() * 2 + 2 + 4]; System.arraycopy(cd, 0, d, 0, cd.length); int urlPos = cd.length; // The length of the unc string, including zero terminator int length = uncString.length() + 1; IntegerHelper.getFourBytes(length, d, urlPos); // Place the string into the stream StringHelper.getUnicodeBytes(uncString, d, urlPos + 4); return d; } /** * Gets the hyperlink stream specific to a local file link * * @param cd the data jxl.common.for all types of hyperlink * @return the raw data for a URL hyperlink */ private byte[] getFileData(byte[] cd) { // Build up the directory hierarchy in reverse order ArrayList path = new ArrayList(); ArrayList shortFileName = new ArrayList(); path.add(file.getName()); shortFileName.add(getShortName(file.getName())); File parent = file.getParentFile(); while (parent != null) { path.add(parent.getName()); shortFileName.add(getShortName(parent.getName())); parent = parent.getParentFile(); } // Deduce the up directory level count and remove the directory from // the path int upLevelCount = 0; int pos = path.size() - 1; boolean upDir = true; while (upDir) { String s = (String) path.get(pos); if (s.equals("..")) { upLevelCount++; path.remove(pos); shortFileName.remove(pos); } else { upDir = false; } pos--; } StringBuffer filePathSB = new StringBuffer(); StringBuffer shortFilePathSB = new StringBuffer(); if (file.getPath().charAt(1)==':') { char driveLetter = file.getPath().charAt(0); if (driveLetter != 'C' && driveLetter != 'c') { filePathSB.append(driveLetter); filePathSB.append(':'); shortFilePathSB.append(driveLetter); shortFilePathSB.append(':'); } } for (int i = path.size() - 1; i >= 0 ; i--) { filePathSB.append((String)path.get(i)); shortFilePathSB.append((String)shortFileName.get(i)); if (i != 0) { filePathSB.append("\\"); shortFilePathSB.append("\\"); } } String filePath = filePathSB.toString(); String shortFilePath = shortFilePathSB.toString(); int dataLength = cd.length + 4 + (shortFilePath.length() + 1) + // short file name 16 + // inexplicable byte sequence 2 + // up directory level count 8 + (filePath.length() + 1) * 2 + // long file name 24; // inexplicable byte sequence if (contents != null) { dataLength += 4 + (contents.length() + 1) * 2; } // Copy across the jxl.common.data into the new array byte[] d = new byte[dataLength]; System.arraycopy(cd, 0, d, 0, cd.length); int filePos = cd.length; // Add in the description text if (contents != null) { IntegerHelper.getFourBytes(contents.length() + 1, d, filePos); StringHelper.getUnicodeBytes(contents, d, filePos + 4); filePos += (contents.length() + 1) * 2 + 4; } int curPos = filePos; // Inexplicable byte sequence d[curPos] = (byte) 0x03; d[curPos+1] = (byte) 0x03; d[curPos+2] = (byte) 0x0; d[curPos+3] = (byte) 0x0; d[curPos+4] = (byte) 0x0; d[curPos+5] = (byte) 0x0; d[curPos+6] = (byte) 0x0; d[curPos+7] = (byte) 0x0; d[curPos+8] = (byte) 0xc0; d[curPos+9] = (byte) 0x0; d[curPos+10] = (byte) 0x0; d[curPos+11] = (byte) 0x0; d[curPos+12] = (byte) 0x0; d[curPos+13] = (byte) 0x0; d[curPos+14] = (byte) 0x0; d[curPos+15] = (byte) 0x46; curPos += 16; // The directory up level count IntegerHelper.getTwoBytes(upLevelCount, d, curPos); curPos += 2; // The number of bytes in the short file name, including zero terminator IntegerHelper.getFourBytes((shortFilePath.length() + 1), d, curPos); // The short file name StringHelper.getBytes(shortFilePath, d, curPos+4); curPos += 4 + (shortFilePath.length() + 1); // Inexplicable byte sequence d[curPos] = (byte) 0xff; d[curPos+1] = (byte) 0xff; d[curPos+2] = (byte) 0xad; d[curPos+3] = (byte) 0xde; d[curPos+4] = (byte) 0x0; d[curPos+5] = (byte) 0x0; d[curPos+6] = (byte) 0x0; d[curPos+7] = (byte) 0x0; d[curPos+8] = (byte) 0x0; d[curPos+9] = (byte) 0x0; d[curPos+10] = (byte) 0x0; d[curPos+11] = (byte) 0x0; d[curPos+12] = (byte) 0x0; d[curPos+13] = (byte) 0x0; d[curPos+14] = (byte) 0x0; d[curPos+15] = (byte) 0x0; d[curPos+16] = (byte) 0x0; d[curPos+17] = (byte) 0x0; d[curPos+18] = (byte) 0x0; d[curPos+19] = (byte) 0x0; d[curPos+20] = (byte) 0x0; d[curPos+21] = (byte) 0x0; d[curPos+22] = (byte) 0x0; d[curPos+23] = (byte) 0x0; curPos += 24; // Size of the long file name data in bytes, including inexplicable data // fields int size = 6 + filePath.length() * 2; IntegerHelper.getFourBytes(size, d, curPos); curPos += 4; // The number of bytes in the long file name // NOT including zero terminator IntegerHelper.getFourBytes((filePath.length()) * 2, d, curPos); curPos += 4; // Inexplicable bytes d[curPos] = (byte) 0x3; d[curPos+1] = (byte) 0x0; curPos += 2; // The long file name StringHelper.getUnicodeBytes(filePath, d, curPos); curPos += (filePath.length() + 1) * 2; /* curPos += 24; int nameLength = filePath.length() * 2; // Size of the file link IntegerHelper.getFourBytes(nameLength+6, d, curPos); // Number of characters IntegerHelper.getFourBytes(nameLength, d, curPos+4); // Inexplicable byte sequence d[curPos+8] = 0x03; // The long file name StringHelper.getUnicodeBytes(filePath, d, curPos+10); */ return d; } /** * Gets the DOS short file name in 8.3 format of the name passed in * * @param s the name * @return the dos short name */ private String getShortName(String s) { int sep = s.indexOf('.'); String prefix = null; String suffix = null; if (sep == -1) { prefix = s; suffix=""; } else { prefix = s.substring(0,sep); suffix = s.substring(sep+1); } if (prefix.length() > 8) { prefix = prefix.substring(0, 6) + "~" + (prefix.length() - 8); prefix = prefix.substring(0, 8); } suffix = suffix.substring(0,Math.min(3, suffix.length())); if (suffix.length() > 0) { return prefix + '.' + suffix; } else { return prefix; } } /** * Gets the hyperlink stream specific to a location link * * @param cd the data jxl.common.for all types of hyperlink * @return the raw data for a URL hyperlink */ private byte[] getLocationData(byte[] cd) { byte[] d = new byte[cd.length + 4 + (location.length() + 1)* 2]; System.arraycopy(cd, 0, d, 0, cd.length); int locPos = cd.length; // The number of chars in the location string, plus a 0 terminator IntegerHelper.getFourBytes(location.length() + 1, d, locPos); // Get the location StringHelper.getUnicodeBytes(location, d, locPos+4); return d; } /** * Initializes the range when this hyperlink is added to the sheet * * @param s the sheet containing this hyperlink */ void initialize(WritableSheet s) { sheet = s; range = new SheetRangeImpl(s, firstColumn, firstRow, lastColumn, lastRow); } /** * Called by the worksheet. Gets the string contents to put into the cell * containing this hyperlink * * @return the string contents for the hyperlink cell */ String getContents() { return contents; } /** * Sets the description * * @param desc the description */ protected void setContents(String desc) { contents = desc; modified = true; } }